package net.lxch.service;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import net.lxch.domain.InterNode;
import net.lxch.domain.MinDistance;
import net.lxch.domain.Point;
import net.lxch.domain.ProductRecord;

import java.util.List;

import static net.lxch.utils.GPSDistanceUtil.getDistance;

/**
 * 模拟器
 */
@Slf4j
public class Simulator {

    /**
     * 内部距离计算表
     */
    private final HashBasedTable<Integer, Integer, Double> table = HashBasedTable.create();
    /**
     * 内部计算节点
     */
    private final List<InterNode> interNodes = Lists.newArrayList();
    /**
     * 配送路径列表
     */
    private List<List<Integer>> routers = Lists.newArrayList();
    /**
     *
     */
    private double minPower;

    /**
     * 计算
     */
    public Simulator(Point point, List<ProductRecord> records) {
        int cur = 0;

        // 加入起点
        interNodes.add(new InterNode(0, point, ""));

        for (ProductRecord record : records) interNodes.add(new InterNode(++cur, record.getPoint(), record.getId()));
    }

    public void simulate() {
        computeRoute();
        log.info("每个点之间的距离 {}", table);
        findRoutes();
        log.info("路径规划 {}", routers);
        log.info("最短路径 {}", findMinDistance());
    }

    /**
     * 计算每两个点之间的距离
     */
    private void computeRoute() {
        // 利用高德地图计算道路路径，填充table路径表
        for (int i = 0; i < interNodes.size(); i++) {
            for (int j = 0; j < interNodes.size(); j++) {
                // todo 计算两点之间距离，需要调用高德接口
//                table.put(i, j, getDistance(interNodes.get(i).getPoint(), interNodes.get(j).getPoint()));
            }
        }
    }

    /**
     * 规划路径
     */
    private void findRoutes() {

        List<InterNode> recordSeq = Lists.newArrayList();
        List<InterNode> others = Lists.newArrayList();

        InterNode startNode = interNodes.remove(0);
        recordSeq.add(startNode);
        others.addAll(interNodes);

        // 去掉首尾的节点后再计算，减少计算时间
        find(recordSeq, others, 0, 0);

    }

    private void find(List<InterNode> recordSeq, List<InterNode> others, double curPower, double minPower) {

        for (int i = 0; i < others.size(); i++) {

            InterNode record = others.get(0);
            recordSeq.add(record);
            others.remove(0);

            if (others.size() == 0) {
                // 方案选择完毕
                List<Integer> router = Lists.newArrayList();
                for (InterNode productRecord : recordSeq) {
                    record = productRecord;
                    router.add(record.getId());
                }
                // 加入终点（同起点）
                router.add(recordSeq.get(0).getId());

                routers.add(router);
            } else {
                find(recordSeq, others, 0, 0);
            }

            // 恢复现场
            record = recordSeq.remove(recordSeq.size() - 1);
            others.add(record);
        }
    }

    /**
     * 从规划路径中选择最短路径
     */
    private MinDistance findMinDistance() {
        MinDistance minDistance = new MinDistance();
        routers.stream().parallel().forEach(router -> {
            double tempDistance = 0;

            for (int j = 0; j < router.size() - 1; j++) {
                tempDistance = tempDistance + table.get(router.get(j), router.get(j + 1));

                // 初始化minDistance
                if (null != minDistance.getDistance()) {
                    if (tempDistance > minDistance.getDistance()) {
                        break;
                    }
                }
            }

            if (null == minDistance.getDistance()) {
                minDistance.setRouter(router);
                minDistance.setDistance(tempDistance);
            } else {
                if (minDistance.getDistance() > tempDistance) {
                    minDistance.setRouter(router);
                    minDistance.setDistance(tempDistance);
                }
            }
        });

        return minDistance;
    }
}